package com.bungarus.group.service;

import com.bungarus.group.cachestore.CacheStore;
import com.bungarus.group.jdbc.GroupMemberManager;
import com.bungarus.group.model.Group;
import com.bungarus.group.model.GroupCacheTransformer;
import com.bungarus.group.model.GroupMember;
import com.bungarus.group.model.Member;
import com.bungarus.group.repo.GroupRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by tang on 2018/12/7.
 */
@Service
public class GroupServiceImpl implements GroupService {
    private GroupRepository repository;
    private GroupMemberManager groupMemberManager;

    private CacheStore cacheStore;
    private GroupCacheTransformer transformer;

    @Autowired
    public GroupServiceImpl(GroupRepository repository, GroupMemberManager groupMemberManager,
                            CacheStore cacheStore, GroupCacheTransformer transformer) {
        this.repository = repository;
        this.groupMemberManager = groupMemberManager;
        this.cacheStore = cacheStore;
        this.transformer = transformer;
    }

    @Override
    public Group createGroup(Group group) {
        if(null == group) {
            throw new IllegalArgumentException("group object cannot be null.");
        }
        else if(group.get_id() <= 0){
            throw new IllegalArgumentException("group id must be greater than zero.");
        }
        else if(group.getTenantId() <= 0) {
            throw new IllegalArgumentException("tenant id in group must be greater than zero.");
        }
        Group result = repository.save(group);
        if(null != result) {
            cacheStore.save(transformer, group);
            if(null != result.getMembers()) {
                this.addMembers(group, group.getMembers());
            }
        }
        return result;
    }

    @Override
    public void deleteGroup(Group group) {
        if(null == group) {
            throw new IllegalArgumentException("input cannot be null.");
        }
        else if(group.get_id() <= 0) {
            throw new IllegalArgumentException("group id must be greater than 0.");
        }
        groupMemberManager.deleteByGid(GroupMember.ofGroup(group));
        cacheStore.delete(
                CacheStore.ofUniqueId(String.valueOf(group.getTenantId()), String.valueOf(group.get_id())),
                transformer);
        repository.deleteById(group.get_id());
    }

    @Override
    public GroupMember addMember(final long gid, Member member) {
        if(gid <= 0 || null == member || member.getId() <= 0){
            throw new IllegalArgumentException("group id or member cannot be null.");
        }

        GroupMember gm = new GroupMember();
        gm.setGid(gid);
        gm.setMid(member.getId());
        gm.setmName(member.getName());
        gm.setgName(UNKNOWN);
        gm.setTenantId(member.getTenantId());

        return this.groupMemberManager.save(gm);
    }

    @Override
    public GroupMember addMember(Group group, Member member) {
        if(null == group || group.get_id() <= 0
                || null == member || member.getId() <= 0){
            throw new IllegalArgumentException("group id or member cannot be null.");
        }
        else if(group.getTenantId() != member.getTenantId()){
            throw new IllegalStateException("tenant id of group and member must be the same.");
        }

        GroupMember gm = new GroupMember();
        gm.setGid(group.get_id());
        gm.setMid(member.getId());
        gm.setmName(member.getName());
        gm.setgName(group.getName());
        gm.setTenantId(member.getTenantId());

        return this.groupMemberManager.save(gm);
    }

    @Override
    public void addMembers(final long gid, final List<Member> members) {
        if(null == members) {
            throw new IllegalArgumentException("members cannot be null.");
        }
        List<GroupMember> gms = members.stream()
                .map(member -> {
                    if (gid <= 0 || member.getId() <= 0) {
                        return null;
                    }
                    GroupMember gm = new GroupMember();
                    gm.setGid(gid);
                    gm.setMid(member.getId());
                    gm.setmName(member.getName());
                    gm.setgName(UNKNOWN);
                    gm.setTenantId(member.getTenantId());
                    return gm;
                })
                .collect(Collectors.toList());

        this.groupMemberManager.saveAll(gms);
    }

    @Override
    public void addMembers(Group group, List<Member> members) {
        if(null == members) {
            throw new IllegalArgumentException("members cannot be null.");
        }
        List<GroupMember> gms = members.stream()
                .map(member -> {
                    if (group.get_id() <= 0 || member.getId() <= 0) {
                        return null;
                    }
                    GroupMember gm = new GroupMember();
                    gm.setGid(group.get_id());
                    gm.setMid(member.getId());
                    gm.setmName(member.getName());
                    gm.setgName(group.getName());
                    gm.setTenantId(member.getTenantId());
                    return gm;
                })
                .collect(Collectors.toList());

        this.groupMemberManager.saveAll(gms);
    }

    @Override
    public List<Member> getMembers(final Group group, final int offset, final int size) {
        int _offset = offset;
        int _size = size;
        if(null == group || group.get_id() <= 0) {
            throw new IllegalArgumentException("group cannot be null or group id must be greater than 0.");
        }
        else if(_offset < 0) {
            _offset = 0;
        }
        else if(size <0 ){
            _size = 20;
        }
        return this.groupMemberManager.findMembers(GroupMember.ofGroup(group), _offset, _size);
    }

    @Override
    public int totalMemberCount(Group group) {
        return this.groupMemberManager.totalMemberCountOfGroup(GroupMember.ofGroup(group));
    }
}
